﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Xml;
using Microsoft.Reporting.WinForms.Internal.Soap.ReportingServices2005.Execution;
using SSRSTestGenerator.Models;
using System.Windows.Input;

namespace SSRSTestGenerator.UserControls
{
    /// <summary>
    /// Interaction logic for LoadReport.xaml
    /// </summary>
    public partial class LoadReport : UserControl
    {
        #region Delegates
        public delegate void SaveReportXml(object sender, ReportXmlArgs arg);
        public event SaveReportXml SavedReportXml;

        public delegate void EditProject();
        public event EditProject EditedProject;

        public delegate void RibbonBarItemUpdate(object sender, List<RibbonMenuItemArgs> arg);
        public event RibbonBarItemUpdate RibbonBarItemUpdated;

        public delegate void NotifyUser(object sender, NotificationArgs arg);
        public event NotifyUser NotifyedUser;
        #endregion

        #region Setters & Getters
        private string username = string.Empty;
        public string ReportUsername
        {
            get { return username; }
            set { username = value; }
        }

        private string domian = string.Empty;
        public string ReportDomian
        {
            get { return domian; }
            set { domian = value; }
        }

        private string password = string.Empty;
        public string ReportPassword
        {
            get { return password; }
            set { password = value; }
        }

        private string reportPath = string.Empty;
        public string ReportPath
        {
            get { return reportPath; }
            set { reportPath = value; }
        }

        private string reportName = string.Empty;
        public string ReportName
        {
            get { return reportName; }
            set { reportName = value; }
        }

        private string reportServiceUrl = string.Empty;
        public string ReportServiceUrl
        {
            get { return reportServiceUrl; }
            set { reportServiceUrl = value; }
        }

        List<RibbonMenuItemArgs> MenuArgs { get; set; }
        App MainApp { get; set; }

        bool ParametersRetrieved { get; set; }
        #endregion

        #region Class Variables
        ServiceReportService2005.ReportingService2005SoapClient rService = new ServiceReportService2005.ReportingService2005SoapClient();
        ReportExecutionService reportExecService = null;

        string format = "xml", devInfo = @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>";
        byte[] reportResult = null;
        string reportNamePath = string.Empty, reportHeaderTextBx = string.Empty, reportTitleTextBx = string.Empty, reportExecutionTimeTextBx = string.Empty, reportPagingTextBx = string.Empty;
        // string reportServiceExecutionUrl = System.Configuration.ConfigurationSettings.AppSettings["ReportExecutionUrl"];
        Microsoft.Reporting.WinForms.Internal.Soap.ReportingServices2005.Execution.Warning[] warnings = null;
        string encoding = null, mimeType = null, extension = null, historyID = null;

        ExecutionInfo execInfo = null;
        ExecutionHeader execHeader = null;
        MemoryStream reportStream = null;
        XmlDocument reportXml = null;
        string[] streamIDs = null;
        ParameterValue[] parameters = null;
        #endregion

        public LoadReport()
        {
            try
            {
                InitializeComponent();

                this.MainApp = ((App)Application.Current); // reference to logging
                this.MainApp.LogMessage("Info","LoadReport entered");
                MenuArgs = new List<RibbonMenuItemArgs>();
                this.ParametersRetrieved = false;
            }
            finally
            {
                this.MainApp.LogMessage("Info","LoadReport exited");
            }
        }

        #region Private Methods
        private void CheckReportWarnings()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","CheckReportWarnings entered");

                // check for report rendering issues
                if (warnings != null)
                {
                    string warning = "Report returned with warning(s). " + Environment.NewLine + Environment.NewLine;
                    foreach (Warning warn in warnings)
                    {
                        warning += "Message: " + warn.Message + " Severity: " + warn.Severity + " Object Name: " + warn.ObjectName + Environment.NewLine;
                    }
                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - " + warning, ImagePath = "/Images/16x16-Error.png" });
                }
                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - No report warnings", ImagePath = "/Images/16x16-Information.png" });
            }
            finally {
                this.MainApp.LogMessage("Info","CheckReportWarnings exited");
                Mouse.OverrideCursor = null; }
        }
        private void LoadStreamIntoXmlObject()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","LoadStreamIntoXmlObject entered");

                this.reportStream = new MemoryStream();
                this.reportStream.Write(this.reportResult, 0, this.reportResult.Length);
                this.reportStream.Position = 0;
                this.reportXml = new XmlDocument();
                this.reportXml.Load(this.reportStream);

                this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Report stream loaded into Xml object successfully", ImagePath = "/Images/16x16-Information.png" });

                ReportXmlArgs args = new ReportXmlArgs(this.reportXml.InnerXml, this.parameters);
                this.SavedReportXml(this, args);                
            }
            finally {
                this.MainApp.LogMessage("Info","LoadStreamIntoXmlObject exited");
                Mouse.OverrideCursor = null; }
        }
        private void GetReportParams(ServiceReportService2005.ReportParameter[] _parameters, List<ReportParameters> lstRptParameters)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","GetReportParams entered");

                foreach (SSRSTestGenerator.ServiceReportService2005.ReportParameter rptParam in _parameters)
                {
                    ReportParameters param = new ReportParameters();
                    param.AllowBlank = rptParam.AllowBlank;
                    param.Name = rptParam.Name;
                    param.Type = rptParam.Type.ToString();
                    if (rptParam.DefaultValues != null)
                    {
                        param.DefaultValues = rptParam.DefaultValues.Count() > 0 ? rptParam.DefaultValues[0] : "";
                    }

                    lstRptParameters.Add(param);
                }

                this.grdParameters.ItemsSource = lstRptParameters;                
                this.EditedProject();  //project has been edited

                if (_parameters.Count() > 0)
                {
                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Report parameters loaded successfully", ImagePath = "/Images/16x16-Information.png" });
                }
                else
                {
                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - No parameters associated with this report", ImagePath = "/Images/16x16-Information.png" });
                }
            }
            finally {
                this.MainApp.LogMessage("Info","GetReportParams exited");
                Mouse.OverrideCursor = null; }
        }
        #endregion

        #region Control Events
        public void CallReport()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","CallReport entered");

                // get parameters
                List<ReportParameters> reportParams = (List<ReportParameters>)this.grdParameters.ItemsSource;

                this.reportExecService = new ReportExecutionService();

                if (!String.IsNullOrEmpty(this.ReportUsername))
                {                    
                    this.reportExecService.Credentials = new System.Net.NetworkCredential(this.ReportUsername, this.ReportPassword, this.ReportDomian);
                }
                else
                {
                    this.reportExecService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                }

                // this.reportExecService.Credentials = System.Net.CredentialCache.DefaultCredentials;                                
                this.reportExecService.Url = this.ReportServiceUrl;
                this.execInfo = new ExecutionInfo();
                this.execHeader = new ExecutionHeader();
                this.reportExecService.ExecutionHeaderValue = this.execHeader;               
                this.reportResult = null;
                {
                    // set report name (to call)
                    string reportPath = String.IsNullOrEmpty(this.ReportPath.Trim()) ? string.Empty : this.ReportPath.Trim();                    
                    reportPath = reportPath.Replace(@"\", @"/");
                    if (reportPath != string.Empty && !reportPath.EndsWith(@"/")) reportPath += @"/";
                    if (reportPath != string.Empty && !reportPath.StartsWith(@"/")) reportPath = @"/" + reportPath;
                    this.reportNamePath = reportPath + this.ReportName;

                    #region Report Parameters
                    if (reportParams != null)
                    {
                        this.parameters = new ParameterValue[reportParams.Count];

                        for (int counter = 0; counter <= reportParams.Count - 1; counter++)
                        {
                            this.parameters[counter] = new ParameterValue();
                            this.parameters[counter].Name = reportParams[counter].Name;
                            this.parameters[counter].Value = reportParams[counter].Value;
                        }
                    }
                    else
                    {
                        this.parameters = new Microsoft.Reporting.WinForms.Internal.Soap.ReportingServices2005.Execution.ParameterValue[0];
                    }
                    #endregion
                   
                    this.execInfo = this.reportExecService.LoadReport(this.reportNamePath, this.historyID);                   
                    this.reportExecService.SetExecutionParameters(this.parameters, string.Empty);

                    this.reportResult = this.reportExecService.Render(this.format, this.devInfo, out this.extension, out this.encoding, out this.mimeType, out this.warnings, out this.streamIDs);
                    this.CheckReportWarnings();
                    this.LoadStreamIntoXmlObject(); // load report (binary) into an XmlDocument object   

                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Report was called successfully", ImagePath = "/Images/16x16-Information.png" });
                    this.EditedProject();  //project has been edited
                }
            }
            finally {
                this.MainApp.LogMessage("Info","CallReport exited");
                Mouse.OverrideCursor = null; }
        }        
        public void GetReportParams()
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","GetReportParams entered");

                List<ReportParameters> lstRptParameters = new List<ReportParameters>();
                reportExecService = new ReportExecutionService();
                reportExecService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                reportExecService.Url = this.ReportServiceUrl;
            
                if (!String.IsNullOrEmpty(this.ReportUsername))
                {
                    rService.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(this.ReportUsername, this.ReportPassword, this.ReportDomian);            
                }
                else
                {
                    if (rService.ClientCredentials.Windows.AllowedImpersonationLevel != System.Security.Principal.TokenImpersonationLevel.Delegation)
                    {
                        rService.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
                    }
                }

                // set report name (to call)
                string reportPath = String.IsNullOrEmpty(this.ReportPath.Trim()) ? string.Empty : this.ReportPath.Trim();
                reportPath = reportPath.Replace(@"\", @"/");

                if (reportPath != string.Empty && !reportPath.EndsWith(@"/")) reportPath += @"/";
                if (reportPath != string.Empty && !reportPath.StartsWith(@"/")) reportPath = @"/" + reportPath;
                this.reportNamePath = reportPath + this.ReportName;

                string _historyID = null;
                bool _forRendering = false;
                ServiceReportService2005.ParameterValue[] _values = null;
                ServiceReportService2005.DataSourceCredentials[] _credentials = null;
                ServiceReportService2005.ReportParameter[] _parameters = null;
               
                rService.GetReportParameters(reportNamePath, _historyID, _forRendering, _values, _credentials, out _parameters);
                if (_parameters.Count() > 0)
                {
                    GetReportParams(_parameters, lstRptParameters); // bind to grid
                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Report parameter(s) successfully retrieved", ImagePath = "/Images/16x16-Information.png" });
                }
                else
                {
                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - No parameters associated with report", ImagePath = "/Images/16x16-Information.png" });
                    MessageBox.Show("No parameters associated with report, click on 'Call Report' to proceed.", "Non-Parameter Report", MessageBoxButton.OK, MessageBoxImage.Information);
                }

                this.grdParameters.IsEnabled = true;                
                this.EditedProject();  //project has been edited
            }
            finally {
                this.MainApp.LogMessage("Info","GetReportParams exited");
                Mouse.OverrideCursor = null; }
        }
        private void grdParameters_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
        {
            try
            {
                this.MainApp.LogMessage("Info","grdParameters_BeginningEdit entered");

                this.EditedProject();  //project has been edited

                // update ribbon menu 
                this.MenuArgs.Clear();
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = true });
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSave", IsRibbonButtonEnabled = true });
                this.RibbonBarItemUpdated(this, MenuArgs);
            }
            finally
            {
                this.MainApp.LogMessage("Info","grdParameters_BeginningEdit exited");
            }
        }
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                this.MainApp.LogMessage("Info","UserControl_Loaded entered");

                this.DetermineRibbonBarMenuItemsStatus(); // work out what can be enabled\disabled in ribbonbar
            }
            finally
            {
                this.MainApp.LogMessage("Info","UserControl_Loaded exited");
                Mouse.OverrideCursor = null;
            }
        }
        #endregion      

        #region Public methods
        public void UpdateReportParameters(ParameterValue[] parameters)
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                this.MainApp.LogMessage("Info","UpdateReportParameters entered");


                if (parameters == null || parameters.Count() == 0) // no report parameters retrieved for this report
                {
                    this.grdParameters.ItemsSource = null;                    
                    this.grdParameters.IsEnabled = false;                    
                    this.ParametersRetrieved = false;

                    // disable saving of parameters (none to save)
                    this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = false });

                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - No parameters have been associated with this report - click the 'Get Report Parameters' button", ImagePath = "/Images/16x16-Information.png" });
                    return;
                }
                else
                {                   
                    List<ReportParameters> lstRptParameters = new List<ReportParameters>();
                    foreach (ParameterValue parameter in parameters)
                    {
                        ReportParameters param = new ReportParameters();
                        param.AllowBlank = true;
                        param.Name = parameter.Name;
                        param.Value = parameter.Value;
                        lstRptParameters.Add(param);
                    }
                    this.grdParameters.ItemsSource = lstRptParameters;
                    this.grdParameters.IsEnabled = true;                   
                    this.ParametersRetrieved = true;

                    // enable saving of parameters
                    this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = true });
                    this.NotifyedUser(this, new NotificationArgs() { Message = this.ReportName + " - Report parameters updated successfully", ImagePath = "/Images/16x16-Valid.png" });
                }                
            }
            finally {
                this.MainApp.LogMessage("Info","UpdateReportParameters exited");
                Mouse.OverrideCursor = null; }
        }
        public ParameterValue[] GetReportParameters()
        {
            try
            {
                this.MainApp.LogMessage("Info","GetReportParameters entered");

                this.grdParameters.CommitEdit(DataGridEditingUnit.Row, true);
                List<ReportParameters> reportParams = (List<ReportParameters>)this.grdParameters.ItemsSource;
                this.parameters = new ParameterValue[reportParams.Count];

                for (int counter = 0; counter <= reportParams.Count - 1; counter++)
                {
                    this.parameters[counter] = new ParameterValue();
                    this.parameters[counter].Name = reportParams[counter].Name;
                    this.parameters[counter].Value = reportParams[counter].Value;
                }

                // enable saving of parameters
                this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = true });
                this.ParametersRetrieved = true;
                return this.parameters;
            }
            finally
            {
                this.MainApp.LogMessage("Info","GetReportParameters exited");
            }
        }
        public void DetermineRibbonBarMenuItemsStatus()
        {
            try
            {
                this.MainApp.LogMessage("Info","DetermineRibbonBarMenuItemsStatus entered");

                // update ribbon menu              
                this.MenuArgs.Clear();

                // parameters
                if (this.ParametersRetrieved) this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = true });
                else this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnSaveParameters", IsRibbonButtonEnabled = false });

                //this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportGerParams", IsRibbonButtonEnabled = true});
                //this.MenuArgs.Add(new RibbonMenuItemArgs() { RibbonButtonName = "btnReportCallReport", IsRibbonButtonEnabled = true });
                
                this.RibbonBarItemUpdated(this, MenuArgs);
            }
            finally
            {
                this.MainApp.LogMessage("Info","DetermineRibbonBarMenuItemsStatus exited");
            }
        }
        #endregion
    }
}
